import Joi from 'joi';
import { ValidationResult, ValidationError } from './types';

// 通用验证工具类
export class ValidationUtils {
  // 验证UUID格式
  static isValidUUID(uuid: string): boolean {
    const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
    return uuidRegex.test(uuid);
  }

  // 验证邮箱格式
  static isValidEmail(email: string): boolean {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }

  // 验证密码强度
  static validatePassword(password: string): ValidationResult {
    const errors: ValidationError[] = [];

    if (password.length < 8) {
      errors.push({
        field: 'password',
        message: '密码长度至少8位',
        value: password.length
      });
    }

    if (!/[A-Z]/.test(password)) {
      errors.push({
        field: 'password',
        message: '密码必须包含至少一个大写字母'
      });
    }

    if (!/[a-z]/.test(password)) {
      errors.push({
        field: 'password',
        message: '密码必须包含至少一个小写字母'
      });
    }

    if (!/\d/.test(password)) {
      errors.push({
        field: 'password',
        message: '密码必须包含至少一个数字'
      });
    }

    if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
      errors.push({
        field: 'password',
        message: '密码必须包含至少一个特殊字符'
      });
    }

    return {
      isValid: errors.length === 0,
      errors
    };
  }

  // 验证SQL脚本名称
  static validateScriptName(name: string): ValidationResult {
    const errors: ValidationError[] = [];

    if (!name || name.trim().length === 0) {
      errors.push({
        field: 'name',
        message: '脚本名称不能为空'
      });
    }

    if (name.length > 255) {
      errors.push({
        field: 'name',
        message: '脚本名称长度不能超过255个字符',
        value: name.length
      });
    }

    // 检查非法字符
    const invalidChars = /[<>:"/\\|?*]/;
    if (invalidChars.test(name)) {
      errors.push({
        field: 'name',
        message: '脚本名称不能包含以下字符: < > : " / \\ | ? *'
      });
    }

    return {
      isValid: errors.length === 0,
      errors
    };
  }

  // 验证数据库连接参数
  static validateConnectionParams(params: any): ValidationResult {
    const schema = Joi.object({
      name: Joi.string().required().max(255).messages({
        'string.empty': '连接名称不能为空',
        'string.max': '连接名称长度不能超过255个字符',
        'any.required': '连接名称是必填项'
      }),
      host: Joi.string().required().max(255).messages({
        'string.empty': '主机地址不能为空',
        'string.max': '主机地址长度不能超过255个字符',
        'any.required': '主机地址是必填项'
      }),
      port: Joi.number().integer().min(1).max(65535).required().messages({
        'number.base': '端口必须是数字',
        'number.integer': '端口必须是整数',
        'number.min': '端口号必须大于0',
        'number.max': '端口号不能超过65535',
        'any.required': '端口是必填项'
      }),
      username: Joi.string().required().max(255).messages({
        'string.empty': '用户名不能为空',
        'string.max': '用户名长度不能超过255个字符',
        'any.required': '用户名是必填项'
      }),
      password: Joi.string().required().messages({
        'string.empty': '密码不能为空',
        'any.required': '密码是必填项'
      }),
      database: Joi.string().optional().max(255).messages({
        'string.max': '数据库名称长度不能超过255个字符'
      }),
      timeout: Joi.number().integer().min(1000).max(300000).optional().messages({
        'number.base': '超时时间必须是数字',
        'number.integer': '超时时间必须是整数',
        'number.min': '超时时间不能少于1秒',
        'number.max': '超时时间不能超过5分钟'
      })
    });

    const { error } = schema.validate(params, { abortEarly: false });
    
    if (error) {
      const errors: ValidationError[] = error.details.map(detail => ({
        field: detail.path.join('.'),
        message: detail.message,
        value: detail.context?.value
      }));

      return {
        isValid: false,
        errors
      };
    }

    return {
      isValid: true,
      errors: []
    };
  }

  // 验证分页参数
  static validatePaginationParams(params: any): ValidationResult {
    const schema = Joi.object({
      page: Joi.number().integer().min(1).optional().messages({
        'number.base': '页码必须是数字',
        'number.integer': '页码必须是整数',
        'number.min': '页码必须大于0'
      }),
      pageSize: Joi.number().integer().min(1).max(100).optional().messages({
        'number.base': '每页大小必须是数字',
        'number.integer': '每页大小必须是整数',
        'number.min': '每页大小必须大于0',
        'number.max': '每页大小不能超过100'
      }),
      sortBy: Joi.string().optional().messages({
        'string.base': '排序字段必须是字符串'
      }),
      sortOrder: Joi.string().valid('asc', 'desc').optional().messages({
        'any.only': '排序方向只能是asc或desc'
      })
    });

    const { error } = schema.validate(params, { abortEarly: false });
    
    if (error) {
      const errors: ValidationError[] = error.details.map(detail => ({
        field: detail.path.join('.'),
        message: detail.message,
        value: detail.context?.value
      }));

      return {
        isValid: false,
        errors
      };
    }

    return {
      isValid: true,
      errors: []
    };
  }

  // 验证SQL内容
  static validateSQLContent(sql: string): ValidationResult {
    const errors: ValidationError[] = [];

    if (!sql || sql.trim().length === 0) {
      errors.push({
        field: 'content',
        message: 'SQL内容不能为空'
      });
      return { isValid: false, errors };
    }

    // 检查SQL长度
    if (sql.length > 1000000) { // 1MB限制
      errors.push({
        field: 'content',
        message: 'SQL内容长度不能超过1MB',
        value: sql.length
      });
    }

    // 检查危险SQL语句（基础检查）
    const dangerousPatterns = [
      /drop\s+database/i,
      /drop\s+table/i,
      /truncate\s+table/i,
      /delete\s+from.*where\s+1\s*=\s*1/i,
      /update.*set.*where\s+1\s*=\s*1/i
    ];

    for (const pattern of dangerousPatterns) {
      if (pattern.test(sql)) {
        errors.push({
          field: 'content',
          message: '检测到潜在危险的SQL语句，请仔细检查'
        });
        break;
      }
    }

    return {
      isValid: errors.length === 0,
      errors
    };
  }

  // 清理和格式化输入
  static sanitizeInput(input: string): string {
    if (typeof input !== 'string') {
      return '';
    }

    return input
      .trim()
      .replace(/\s+/g, ' ') // 多个空格替换为单个空格
      .replace(/[\x00-\x1f\x7f]/g, ''); // 移除控制字符
  }

  // 验证文件上传
  static validateFileUpload(file: any, allowedTypes: string[], maxSize: number): ValidationResult {
    const errors: ValidationError[] = [];

    if (!file) {
      errors.push({
        field: 'file',
        message: '文件不能为空'
      });
      return { isValid: false, errors };
    }

    // 检查文件类型
    if (allowedTypes.length > 0 && !allowedTypes.includes(file.mimetype)) {
      errors.push({
        field: 'file',
        message: `不支持的文件类型，允许的类型: ${allowedTypes.join(', ')}`,
        value: file.mimetype
      });
    }

    // 检查文件大小
    if (file.size > maxSize) {
      errors.push({
        field: 'file',
        message: `文件大小超过限制，最大允许: ${this.formatFileSize(maxSize)}`,
        value: this.formatFileSize(file.size)
      });
    }

    return {
      isValid: errors.length === 0,
      errors
    };
  }

  // 格式化文件大小
  static formatFileSize(bytes: number): string {
    if (bytes === 0) return '0 Bytes';

    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  // 验证标签
  static validateTags(tags: string[]): ValidationResult {
    const errors: ValidationError[] = [];

    if (!Array.isArray(tags)) {
      errors.push({
        field: 'tags',
        message: '标签必须是数组格式'
      });
      return { isValid: false, errors };
    }

    if (tags.length > 20) {
      errors.push({
        field: 'tags',
        message: '标签数量不能超过20个',
        value: tags.length
      });
    }

    for (let i = 0; i < tags.length; i++) {
      const tag = tags[i];
      
      if (typeof tag !== 'string') {
        errors.push({
          field: `tags[${i}]`,
          message: '标签必须是字符串'
        });
        continue;
      }

      if (tag.length > 50) {
        errors.push({
          field: `tags[${i}]`,
          message: '单个标签长度不能超过50个字符',
          value: tag.length
        });
      }

      if (!/^[a-zA-Z0-9\u4e00-\u9fa5_-]+$/.test(tag)) {
        errors.push({
          field: `tags[${i}]`,
          message: '标签只能包含字母、数字、中文、下划线和连字符',
          value: tag
        });
      }
    }

    return {
      isValid: errors.length === 0,
      errors
    };
  }
}